package com.seed.core.pojo.seed;

import cn.hutool.core.util.StrUtil;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.mybatisflex.core.query.QueryColumn;
import com.mybatisflex.core.query.QueryCondition;
import com.mybatisflex.core.query.QueryTable;
import com.seed.core.annotation.HasOne;
import com.seed.core.enumeration.Cascade;
import com.seed.core.pojo.Const;
import com.seed.util.RowKit;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

@JsonInclude(JsonInclude.Include.NON_NULL)
public class HasOnes extends BelongsTos {
    protected Cascade cascade;

//    public HasOnes of(Class<?> selfEntityClass, Class<?> targetEntityClass, HasOne hasOne) {
//        setExtraType(hasOne.extraType());
//        setSelfEntityClass(selfEntityClass);
//        setTargetEntityClass(targetEntityClass);
//        setSelfColumn(hasOne.selfColumn());
//        setTargetColumn(hasOne.targetColumn());
//        setLabel(hasOne.label());
//        setComment(hasOne.comment());
//        setCascade(hasOne.cascade());
//        setExtra(hasOne.extra());
//
//        return this;
//    }

    public HasOnes of(Map<Class<?>, Seed> seeds, Class<?> selfEntityClass, Class<?> targetEntityClass, HasOne hasOne) {
        setSelfSeed(seeds.get(selfEntityClass));
        setTargetSeed(seeds.get(targetEntityClass));
        setTargetSeedName(targetSeed.getName());

        setSelfEntityClass(selfEntityClass);
        setTargetEntityClass(targetEntityClass);

        setSelfColumn(hasOne.selfColumn());
        setTargetColumn(hasOne.targetColumn());
        setLabel(hasOne.label());
        setComment(hasOne.comment());

        setExtra(hasOne.extra());

        setCascade(hasOne.cascade());

        return this;
    }

    @Override
    public Seed getExtraSeed() {
        return targetSeed;
    }

    public HasOnes clone() {
        HasOnes ret = new HasOnes();
        ret.setTargetSeedName(targetSeedName);
        ret.setSelfSeed(selfSeed);
        ret.setTargetSeed(targetSeed);
        ret.setSelfEntityClass(selfEntityClass);
        ret.setTargetEntityClass(targetEntityClass);
        ret.setSelfColumn(selfColumn);
        ret.setTargetColumn(targetColumn);
        ret.setLabel(label);
        ret.setComment(comment);

        if(extra != null) ret.setExtra(new HashMap<>(extra));

        ret.setCascade(cascade);

        return ret;
    }

//    public QueryCondition getQueryCondition(String basePath, String cross) {
//        String selfTableAlias = StrKit.selfTableAlias(basePath);
//        String targetTableAlias = StrKit.targetTableAlias(basePath, cross);
//        return getQueryCondition(selfTableAlias, targetTableAlias, targetTableAlias);
//    }

//    public QueryCondition getQueryCondition(List<?> selfList, String targetTableAlias) {
//        QueryTable targetTable = new QueryTable(targetSeed.getTableName()).as(targetTableAlias);
//        String inferTargetColumn = inferTargetColumn();
//
//        String selfField = StrUtil.toCamelCase(inferSelfColumn());
//        QueryCondition ret = new QueryColumn(targetTable, inferTargetColumn).in(RowKit.getSelfValues(selfList, selfField));
//        for(Map.Entry<String, Object> entry: getColumnAndValues().entrySet()) {
//            ret.and(new QueryColumn(targetTable, entry.getKey()).eq(entry.getValue()));
//        }
//
//        return ret;
//    }

//    public QueryCondition getQueryCondition(List<?> selfList, String targetTableAlias) {
//        QueryTable targetTable = new QueryTable(targetSeed.getTableName()).as(targetTableAlias);
//        String inferTargetColumn = inferTargetColumn();
//
//        String selfField = selfField();
//        if(condition == null || condition.length == 0) {
//            return new QueryColumn(targetTable, inferTargetColumn).in(RowKit.getSelfValues(selfList, selfField));
//        }
//
//        QueryCondition ret = hasCrossField()
//            ? new QueryColumn(targetTable, inferTargetColumn).in(RowKit.getSelfValues(selfList, selfField))
//            : QueryCondition.createEmpty();
//
//        for(String c: condition) {
//            Map<TableType, Set<String>> columns = getConditionColumns();
//            for(Map.Entry<TableType, Set<String>> entry: columns.entrySet()) {
//                TableType tableType = entry.getKey();
//                Set<String> columnNames = entry.getValue();
//                for (String columnName: columnNames) {
//                    switch (tableType) {
//                        case through, target -> {
//                            String replacement = String.format("`%s`.`%s`", targetTableAlias, columnName);
//                            c = c.replace(String.format("`%s.%s`", tableType, columnName), replacement);
//                        }
//                    }
//                }
//            }
//            ret.and(c);
//        }
//
//        return ret;
//    }

//    public QueryCondition getQueryCondition(Object self, String targetTableAlias) {
//        QueryTable targetTable = new QueryTable(targetSeed.getTableName()).as(targetTableAlias);
//        String inferTargetColumn = inferTargetColumn();
//
//        if(condition == null || condition.length == 0) {
//            return new QueryColumn(targetTable, inferTargetColumn).eq(RowKit.getSelfValue(self, StrUtil.toCamelCase(inferSelfColumn())));
//        }
//
//        QueryCondition ret = hasCrossField()
//                ? new QueryColumn(targetTable, inferTargetColumn).eq(RowKit.getSelfValue(self, StrUtil.toCamelCase(inferSelfColumn())))
//                : QueryCondition.createEmpty();
//
//        for(String c: condition) {
//            Map<TableType, Set<String>> columns = getConditionColumns();
//            for(Map.Entry<TableType, Set<String>> entry: columns.entrySet()) {
//                TableType tableType = entry.getKey();
//                Set<String> columnNames = entry.getValue();
//                for (String columnName: columnNames) {
//                    switch (tableType) {
//                        case self -> {
//                            Object selfValue = RowKit.getSelfValue(self, columnName);
//                            String realValue = selfValue instanceof String ? String.format("'%s'", selfValue) : selfValue.toString();
//                            c = c.replace(String.format("`%s.%s`", tableType, columnName), realValue);
//                        }
//                        case through, target -> {
//                            if(StrUtil.isBlank(targetTableAlias)) {
//                                String replacement = String.format("`%s`", columnName);
//                                c = c.replace(String.format("`%s.%s`", tableType, columnName), replacement);
//                            } else {
//                                String replacement = String.format("`%s`.`%s`", targetTableAlias, columnName);
//                                c = c.replace(String.format("`%s.%s`", tableType, columnName), replacement);
//                            }
//                        }
//                    }
//                }
//            }
//            ret.and(c);
//        }
//
//        return ret;
//    }

//    public QueryCondition getQueryCondition(Object self, String targetTableAlias) {
//        QueryTable targetTable = new QueryTable(targetSeed.getTableName()).as(targetTableAlias);
//        String inferTargetColumn = inferTargetColumn();
//
//        String selfField = StrUtil.toCamelCase(inferSelfColumn());
//        QueryCondition ret = new QueryColumn(targetTable, inferTargetColumn).eq(RowKit.getSelfValue(self, selfField));
//        for(Map.Entry<String, Object> entry: getColumnAndValues().entrySet()) {
//            ret.and(new QueryColumn(targetTable, entry.getKey()).eq(entry.getValue()));
//        }
//
//        return ret;
//    }

    public String inferSelfColumn() {
        if(StrUtil.isBlank(selfColumn)) return Const.ID;

        return StrUtil.toUnderlineCase(selfColumn);
    }

    public String inferTargetColumn() {
        if(StrUtil.isBlank(targetColumn)) return StrUtil.toUnderlineCase(StrUtil.lowerFirst(selfSeed.getName())) + "_" + Const.ID;

        return StrUtil.toUnderlineCase(targetColumn);
    }

    public Cascade getCascade() {
        return cascade;
    }

    public void setCascade(Cascade cascade) {
        this.cascade = cascade;
    }
}
